"""
Models for AST
"""

from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Dict, List, Literal, OrderedDict, Tuple, Union

from clang.cindex import CursorKind
from dataclasses_json import DataClassJsonMixin


if TYPE_CHECKING:
    CursorKind: Any = CursorKind


@dataclass
class VarRef(DataClassJsonMixin):
    type: Literal["global", "local"]
    identifier: str


def _to_str(obj) -> str:
    attrs = [f"id={id(obj)}"] + [
        f"{k}" + "=" + (v.to_str() if hasattr(v, "to_str") else str(v))
        for k, v in obj.__dict__.items()
    ]
    attrs_str = ", ".join(attrs)
    return f"{obj.__class__.__name__}({attrs_str})"


class Variable:
    """
    可被访问的变量，可以是全局变量或局部变量
    """

    value: "ConcreteValueType"

    def __init__(self, value: "ConcreteValueType"):
        self.value = value

    def __repr__(self) -> str:
        return _to_str(self)


class BaseValue:
    def to_str(self) -> str:
        return _to_str(self)

    def __repr__(self) -> str:
        return self.to_str()


# @dataclas/s
class StructValue(BaseValue):
    attributes: Dict[str, Variable]

    def __init__(self, attributes: Dict[str, Variable]):
        self.attributes = attributes

    # type: Optional["StructType"] = None
    def shallow_copy(self):
        d = {k: _shallow_copy_variable(v) for k, v in self.attributes.items()}
        return StructValue(d)


class ArrayValue(BaseValue):
    values: List[Variable]

    def __init__(self, values: List[Variable]) -> None:
        self.values = values


class PointerValue(BaseValue):
    pointee: Variable

    def __init__(self, pointee: Variable) -> None:
        self.pointee = pointee


class FunctionValue(BaseValue):
    """
    Callable value representing a function
    """

    def __init__(self, name: str) -> None:
        self.name = name


class ArrayInitializerValue(BaseValue):

    def __init__(self, values: List["ConcreteValueType"]) -> None:
        self.values = values


def _shallow_copy_variable(var: Variable) -> Variable:
    match var.value:
        case int() | str() | bool() | float():
            return Variable(var.value)
        case StructValue():
            return Variable(
                StructValue(
                    {k: Variable(v.value) for k, v in var.value.attributes.items()}
                )
            )
        case _:
            raise ValueError(f"Cannot shallow copy variable {var}")


ConcreteValueType = Union[
    StructValue,
    ArrayValue,
    PointerValue,
    None,
    str,
    int,
    float,
    bool,
    FunctionValue,
    ArrayInitializerValue,
]

DATA_TYPE = Union[
    "StructType", "ArrayType", Literal["integer", "char", "float", "string"]
]


@dataclass
class StructType:
    attr_types: List[Tuple[str, DATA_TYPE]]


@dataclass
class ArrayType:
    element_type: DATA_TYPE
